package com.ctrip.framework.apollo.configservice;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;

import com.ctrip.framework.apollo.biz.config.BizConfig;
import com.ctrip.framework.apollo.biz.grayReleaseRule.GrayReleaseRulesHolder;
import com.ctrip.framework.apollo.biz.message.ReleaseMessageScanner;
import com.ctrip.framework.apollo.configservice.controller.ConfigFileController;
import com.ctrip.framework.apollo.configservice.controller.NotificationController;
import com.ctrip.framework.apollo.configservice.controller.NotificationControllerV2;
import com.ctrip.framework.apollo.configservice.filter.ClientAuthenticationFilter;
import com.ctrip.framework.apollo.configservice.service.ReleaseMessageServiceWithCache;
import com.ctrip.framework.apollo.configservice.service.config.ConfigService;
import com.ctrip.framework.apollo.configservice.service.config.ConfigServiceWithCache;
import com.ctrip.framework.apollo.configservice.service.config.DefaultConfigService;
import com.ctrip.framework.apollo.configservice.util.AccessKeyUtil;

/**
 * @author Jason Song(song_s@ctrip.com)
 */
@Configuration
public class ConfigServiceAutoConfiguration {

	private final BizConfig bizConfig;

	public ConfigServiceAutoConfiguration(final BizConfig bizConfig) {
		this.bizConfig = bizConfig;
	}

	@Bean
	public GrayReleaseRulesHolder grayReleaseRulesHolder() {
		return new GrayReleaseRulesHolder();
	}

	// 最终有两个子类，差异点在于是否使用缓存，通过ServerConfig"config-service.cache.enabled"配置，默认关闭。开启后能提高性能，但是会增大内存消耗
	@Bean
	public ConfigService configService() {
		// 开启缓存，使用ConfigServiceWithCache
		if (bizConfig.isConfigServiceCacheEnabled()) {
			return new ConfigServiceWithCache();
		}
		// 不开启缓存，使用DefaultConfigService
		return new DefaultConfigService();
	}

	@Bean
	public static NoOpPasswordEncoder passwordEncoder() {
		return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
	}

	@Bean
	public FilterRegistrationBean clientAuthenticationFilter(AccessKeyUtil accessKeyUtil) {
		FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();

		filterRegistrationBean.setFilter(new ClientAuthenticationFilter(accessKeyUtil));
		filterRegistrationBean.addUrlPatterns("/configs/*");
		filterRegistrationBean.addUrlPatterns("/configfiles/*");
		filterRegistrationBean.addUrlPatterns("/notifications/v2/*");

		return filterRegistrationBean;
	}

	@Configuration
	static class MessageScannerConfiguration {
		private final NotificationController notificationController;
		private final ConfigFileController configFileController;
		private final NotificationControllerV2 notificationControllerV2;
		private final GrayReleaseRulesHolder grayReleaseRulesHolder;
		private final ReleaseMessageServiceWithCache releaseMessageServiceWithCache;
		private final ConfigService configService;

		public MessageScannerConfiguration(final NotificationController notificationController,
				final ConfigFileController configFileController,
				final NotificationControllerV2 notificationControllerV2,
				final GrayReleaseRulesHolder grayReleaseRulesHolder,
				final ReleaseMessageServiceWithCache releaseMessageServiceWithCache,
				final ConfigService configService) {
			this.notificationController = notificationController;
			this.configFileController = configFileController;
			this.notificationControllerV2 = notificationControllerV2;
			this.grayReleaseRulesHolder = grayReleaseRulesHolder;
			this.releaseMessageServiceWithCache = releaseMessageServiceWithCache;
			this.configService = configService;
		}

		@Bean
		public ReleaseMessageScanner releaseMessageScanner() {
			ReleaseMessageScanner releaseMessageScanner = new ReleaseMessageScanner();
			// 0. handle release message cache
			releaseMessageScanner.addMessageListener(releaseMessageServiceWithCache);
			// 1. handle gray release rule
			releaseMessageScanner.addMessageListener(grayReleaseRulesHolder);
			// 2. handle server cache
			releaseMessageScanner.addMessageListener(configService);
			releaseMessageScanner.addMessageListener(configFileController);
			// 3. notify clients
			releaseMessageScanner.addMessageListener(notificationControllerV2);
			releaseMessageScanner.addMessageListener(notificationController);
			return releaseMessageScanner;
		}
	}

}
